﻿using ED.Common.Extensions;
using ED.Common.Filters;
using ED.Cousul;
using ED.FreeSql.Core;
using ED.EFCore;
using ED.FreeRedis;
using ED.GRPC;
using ED.HangFire;
using ED.MiniProfiler;
using ED.RabbitMQ;
using FluentValidation;
using FluentValidation.AspNetCore;
using IGeekFan.AspNetCore.Knife4jUI;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.OpenApi.Models;
using OpenIddict.Validation.AspNetCore;
using System.Reflection;
using UserCenter;
using FreeSql;

namespace ED.Admin.Extensions
{
    /// <summary>
    /// 扩展配置项
    /// </summary>
    public class AdminExtensions : ExtensionsBase
    {
        #region OpenId
        /// <summary>
        /// AddOpenIdDict
        /// </summary>
        /// <returns></returns>
        public IServiceCollection AddOpenIdDict()
        {
            #region OpenId 配置
            Services.AddOpenIddict()
    .AddValidation(options =>
    {
        // Note: the validation handler uses OpenID Connect discovery
        // to retrieve the address of the introspection endpoint.

        options.SetIssuer(Configuration.GetSection("OpenId:AuthUrl").Value);
        options.AddAudiences(Configuration.GetSection("OpenId:Audiences").Value);

        // Configure the validation handler to use introspection and register the client
        // credentials used when communicating with the remote introspection endpoint.
        options.UseIntrospection()
               .SetClientId(Configuration.GetSection("OpenId:Audiences").Value)
               .SetClientSecret(Configuration.GetSection("OpenId:ClientSecret").Value);

        // Register the System.Net.Http integration.
        options.UseSystemNetHttp();

        // Register the ASP.NET Core host.
        options.UseAspNetCore();
    });

            Services.AddAuthentication(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
            Services.AddAuthorization();
            return Services;
            #endregion
        }
        #endregion
        #region MVC配置
        /// <summary>
        /// Controller
        /// </summary>
        /// <param name="action"></param>
        /// <param name="jsonOptions"></param>
        /// <returns></returns>
        public IServiceCollection Controller(Action<MvcOptions>? action = null, Action<MvcNewtonsoftJsonOptions>? jsonOptions = null)
        {
            // 禁用默认ModelState行为
            Services.Configure<ApiBehaviorOptions>(options =>
            {
                options.SuppressModelStateInvalidFilter = true;
            });
            Services.Configure(delegate (FormOptions options)
            {
                options.MultipartBodyLengthLimit = long.MaxValue;
            });
            Services.AddControllers(delegate (MvcOptions options)
            {
                action?.Invoke(options); // 将传过来的委托拿过来执行 相当于将传过来的配置项复制到该地
                options.Filters.Add<MyExceptionFilter>();
               // options.Filters.Add<LogActionFilter>();
               // options.Filters.Add<ModelValidationFilter>();
            });
            //Services.AddFluentValidationAutoValidation();
            //Services.AddValidatorsFromAssembly(Assembly.Load("ED.Model"));
            //Services.AddHealthChecks();
            MVC(jsonOptions);
            Services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "API V1", Version = "v1" });
                c.AddServer(new OpenApiServer()
                {
                    Url = "",
                    Description = "vvv"
                });
                c.CustomOperationIds(apiDesc =>
                {
                    var controllerAction = apiDesc.ActionDescriptor as ControllerActionDescriptor;
                    return controllerAction.ActionName;
                });
                c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "WebAPI.xml"), true);
            });

            return Services;
        }

        private IServiceCollection MVC(Action<MvcNewtonsoftJsonOptions>? jsonOptions = null)
        {
            Services.AddMvc(delegate (MvcOptions c)
            {
                c.EnableEndpointRouting = false;
            }).AddNewtonsoftJson(delegate (MvcNewtonsoftJsonOptions options)
            {
                jsonOptions?.Invoke(options);
            });
            Services.AddCors(option => option.AddPolicy("cors", policy => policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()));
            return Services;
        }
        #endregion
        #region AutoMapper
        /// <summary>
        /// AddAutoMapper
        /// </summary>
        /// <returns></returns>
        public IServiceCollection AddAutoMapper()
        {
            Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
            return Services;
        }

        #endregion
        #region AddORM
        /// <summary>
        /// AddORM
        /// </summary>
        public void AddORM()
        {
            Services.AddFreeSql(DataType.MySql,Configuration.GetConnectionString("SqlConnectionString"));
           // Services.AddEFCore(t => t.SqlConnectionString = Configuration.GetConnectionString("SqlConnectionString"));
        }
        #endregion
        #region 注册Redis
        /// <summary>
        /// 注册Redis
        /// </summary>
        public void AddFreeRedis()
        {
            Services.AddFreeRedis(options =>
            {
                options.RedisUrl = Configuration.GetSection("Redis").Value.ToString();
            });
        }
        #endregion
        #region 注册RabbitMQ
        /// <summary>
        /// 注册RabbitMQ
        /// </summary>
        public void AddRabbitMQ()
        {
            Services.AddRabbitMQ(options =>
            {
                options.HostName = Configuration.GetSection("RabbitMQServer:HostName").Value;
                options.Port = Configuration.GetSection("RabbitMQServer:Port").Value.To<int>();
                options.UserName = Configuration.GetSection("RabbitMQServer:UserName").Value;
                options.Password = Configuration.GetSection("RabbitMQServer:Password").Value;
            });
        }
        #endregion
        #region 注册Cousul
        /// <summary>
        /// 注册Cousul
        /// </summary>
        /// <returns></returns>
        public void AddConsul()
        {

            Services.AddConsul();
        }
        #endregion
        #region AddMiniProfiler
        /// <summary>
        /// AddMiniProfiler
        /// </summary>
        public void AddMiniProfiler()
        {
            Services.AddCustomMiniProfiler();
        }
        #endregion
        #region 注册Log

        #endregion
        #region 注入GRPC
        /// <summary>
        /// 注入GRPC
        /// </summary>
        public void AddGrpc()
        {
            Services.AddScoped(typeof(IGRPCExtions<>), typeof(GRPCExtions<>));
        }
        #endregion
        #region 注册Mongodb

        #endregion
        #region 注册任务调度器
        /// <summary>
        /// AddHangfire
        /// </summary>
        public void AddHangfire()
        {
            Services.AddCustomHangFire(Configuration.GetConnectionString("SqlConnectionString"));
        }
        #endregion
        #region 全局服务注册
        /// <summary>
        /// 全局服务注册
        /// </summary>
        public void AddServices()
        {
            AddAllServices(Services);
        }
        #endregion
        /// <summary>
        /// App配置
        /// </summary>
        public void AppConfig()
        {
            app.UseFreeSql();

            //app.UseMiniProfiler();
            app.UseSwagger();
            app.UseKnife4UI(c =>
            {
                c.RoutePrefix = ""; // serve the UI at root
                c.SwaggerEndpoint("/v1/api-docs", "V1 Docs");
            });
            app.UseHttpsRedirection();
            app.UseCors("cors");
            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseConsul();
            app.UseHangFire();
            app.Use(async (ctx, next) =>
            {
                if (ctx.Request.Path == "/health")
                {
                    await ctx.Response.WriteAsync($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} gateway is running...");
                    return;
                }
                await next();
            });
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                endpoints.MapSwagger("{documentName}/api-docs");
            });
            app.Run();
        }

        /// <summary>
        /// 所有注册接口
        /// </summary>
        public void AddAllServices(IServiceCollection services)
        {
            AppDomain.CurrentDomain.GetAssemblies().Where(t => t.GetName().Name.Contains("ED.")).ToList().ForEach(assembly =>
            {
                var serviceTypes = assembly.GetTypes()
         .Where(x => x.IsClass && !x.IsAbstract && !x.IsGenericType)
         .Select(x => new
         {
             Service = x.GetInterfaces().FirstOrDefault(i => i.Name == "I" + x.Name),
             Implementation = x
         })
         .Where(x => x.Service != null)
         .ToList();

                foreach (var serviceType in serviceTypes)
                {
                    if (serviceType.Service != null)
                    {
                        services.AddSingleton(serviceType.Service, serviceType.Implementation);
                    }
                }
            });

        }

        /// <summary>
        /// 注入用户中心
        /// </summary>
        public void AddUserCenter()
        {
            Services.AddHttpContextAccessor();
            Services.AddScoped<IUser, User>();
            Services.AddScoped<IHeaderExt, HeaderExt>();
        }

        /// <summary>
        /// 获取全部 Assembly
        /// </summary>
        /// <returns></returns>
        private List<Assembly> GetAllAssembly()
        {

            var allAssemblies = AppDomain.CurrentDomain.GetAssemblies().Where(t => t.GetName().Name.Contains("Repository")).ToList();
            return allAssemblies;
        }
    }
}
